package com.quan.commons.utils;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * Web层辅助类
 *
 * @author yhaoquan
 */
public final class WebUtils {

    private static final Logger logger = LoggerFactory.getLogger(WebUtils.class);

    private static final String ENCODING = "UTF-8";

    private WebUtils() {
    }

    /**
     * 判断请求是否为 AJAX
     *
     * @param request
     * @return
     */
    public static boolean isAjax(HttpServletRequest request) {
        return (request.getHeader("X-Requested-With") != null && "XMLHttpRequest".equals(request.getHeader("X-Requested-With").toString()));
    }

    /**
     * AJAX 设置 response 返回状态
     *
     * @param response
     * @param status
     * @param tip
     */
    public static void ajaxStatus(HttpServletResponse response, int status, String tip) {
        try {
            response.setContentType("text/html;charset=" + ENCODING);
            response.setStatus(status);
            PrintWriter out = response.getWriter();
            out.print(tip);
            out.flush();
        } catch (IOException e) {
            logger.error(e.toString());
        }
    }

    /**
     * 获取状态码
     *
     * @param request
     * @return
     */
    public static HttpStatus getStatus(HttpServletRequest request) {
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
        if (statusCode == null) {
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }
        return HttpStatus.valueOf(statusCode);
    }

    /**
     * 获取当前 URL 包含查询条件
     *
     * @param request
     * @param encode
     * @return
     * @throws IOException
     */
    public static String getQueryString(HttpServletRequest request, String encode) throws IOException {
        StringBuffer sb = new StringBuffer(request.getRequestURL());
        String query = request.getQueryString();
        if (query != null && query.length() > 0) {
            sb.append("?").append(query);
        }
        return URLEncoder.encode(sb.toString(), encode);
    }

    /**
     * getRequestURL是否包含在URL之内
     *
     * @param request
     * @param url
     * @return
     */
    public static boolean inContainURL(HttpServletRequest request, String url) {
        boolean result = false;
        if (url != null && !"".equals(url.trim())) {
            String[] urlArr = url.split(";");
            StringBuffer reqUrl = new StringBuffer(request.getRequestURL());
            for (int i = 0; i < urlArr.length; i++) {
                if (reqUrl.indexOf(urlArr[i]) > 1) {
                    result = true;
                    break;
                }
            }
        }
        return result;
    }

    /**
     * URLEncoder 返回地址
     *
     * @param url      跳转地址
     * @param retParam 返回地址参数名
     * @param retUrl   返回地址
     * @return
     */
    public static String encodeRetURL(String url, String retParam, String retUrl) {
        return encodeRetURL(url, retParam, retUrl, null);
    }

    /**
     * URLEncoder 返回地址
     *
     * @param url      跳转地址
     * @param retParam 返回地址参数名
     * @param retUrl   返回地址
     * @param data     携带参数
     * @return
     */
    public static String encodeRetURL(String url, String retParam, String retUrl, Map<String, String> data) {
        if (url == null) {
            return null;
        }

        StringBuffer retStr = new StringBuffer(url);
        retStr.append("?");
        retStr.append(retParam);
        retStr.append("=");
        try {
            retStr.append(URLEncoder.encode(retUrl, ENCODING));
        } catch (UnsupportedEncodingException e) {
            logger.error("encodeRetURL error." + url);
            e.printStackTrace();
        }

        if (data != null) {
            for (Map.Entry<String, String> entry : data.entrySet()) {
                retStr.append("&").append(entry.getKey()).append("=").append(entry.getValue());
            }
        }

        return retStr.toString();
    }

    /**
     * URLDecoder 解码地址
     *
     * @param url
     * @return
     */
    public static String decodeURL(String url) {
        if (url == null) {
            return null;
        }
        String retUrl = "";
        try {
            retUrl = URLDecoder.decode(url, ENCODING);
        } catch (UnsupportedEncodingException e) {
            logger.error("encodeRetURL error." + url);
            e.printStackTrace();
        }
        return retUrl;
    }

    /**
     * URLEncoder 编码地址
     *
     * @param url
     * @return
     */
    public static String encodeURL(String url) {
        if (url == null) {
            return null;
        }
        String retUrl = "";
        try {
            retUrl = URLEncoder.encode(url, ENCODING);
        } catch (UnsupportedEncodingException e) {
            logger.error("encodeRetURL error." + url);
            e.printStackTrace();
        }
        return retUrl;
    }

    /**
     * 编码
     *
     * @param content
     * @return
     */
    public static String encode(String content) {
        return encodeURL(content);
    }

    /**
     * 解码
     *
     * @param content
     * @return
     */
    public static String decode(String content) {
        return decodeURL(content);
    }

    /**
     * 判断是否 GET 请求
     *
     * @param request
     * @return
     */
    public static boolean isGet(HttpServletRequest request) {
        if ("GET".equalsIgnoreCase(request.getMethod())) {
            return true;
        }
        return false;
    }

    /**
     * 判断是否 POST 请求
     *
     * @param request
     * @return
     */
    public static boolean isPost(HttpServletRequest request) {
        if ("POST".equalsIgnoreCase(request.getMethod())) {
            return true;
        }
        return false;
    }

    /**
     * 请求重定向至地址 location
     *
     * @param response 请求响应
     * @param location 重定向至地址
     */
    public static void sendRedirect(HttpServletResponse response, String location) {
        try {
            response.sendRedirect(location);
        } catch (IOException e) {
            logger.error("sendRedirect location:" + location);
            e.printStackTrace();
        }
    }

    /**
     * 获取Request Playload 内容
     *
     * @param request
     * @return Playload 内容
     * @throws IOException
     */
    public static String requestPlayload(HttpServletRequest request) throws IOException {
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader = null;
        try {
            InputStream inputStream = request.getInputStream();
            if (inputStream != null) {
                bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                char[] charBuffer = new char[128];
                int bytesRead = -1;
                while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                    stringBuilder.append(charBuffer, 0, bytesRead);
                }
            } else {
                stringBuilder.append("");
            }
        } catch (IOException ex) {
            throw ex;
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException ex) {
                    throw ex;
                }
            }
        }
        return stringBuilder.toString();
    }

    /**
     * 获取IP地址
     *
     * @param request
     * @return
     */
    public static final String getIpAddress(HttpServletRequest request) {
        return IpHelper.getIpAddr(request);
    }

    /**
     * 获取项目上下文路径
     *
     * @param request
     * @return
     */
    public static final String getContextPath(HttpServletRequest request) {
        return request.getSession().getServletContext().getContextPath();
    }

    /**
     * 上一次请求的地址
     *
     * @param request
     * @return
     */
    public static String getBackURL(HttpServletRequest request) {
        if (null != request) {
            String url = request.getParameter("preRequest");
            // 使用Filter时 文件上传时 getParameter时为null 所以改成Interceptor
            if (StringUtils.isEmpty(url)) {
                url = request.getHeader("Referer");
            }
            if (!StringUtils.isEmpty(url) && (url.startsWith("http://") || url.startsWith("https://"))) {
                return url;
            }
            if (!StringUtils.isEmpty(url) && url.startsWith(request.getContextPath())) {
                url = getDomain(request) + url;
            }
            return url;
        }
        return null;
    }

    /**
     * 获取当前访问的URL地址
     *
     * @param request
     * @param needQueryString
     * @return
     */
    public static String getCurrentUrl(HttpServletRequest request, boolean needQueryString) {
        try {
            String url = request.getRequestURI();
            String queryString = request.getQueryString();
            if (!StringUtils.isEmpty(queryString)) {
                queryString = "?" + queryString;
                if (queryString.startsWith("&")) {
                    queryString = "?" + queryString.substring(1);
                }
            }
            if (!StringUtils.isEmpty(queryString) && needQueryString) {
                url = url + queryString;
            }
            return getDomain(request) + url;
        } catch (NullPointerException e) {
            logger.error("无法取得HttpServletRequest对象：{}", e.getMessage());
        }
        return null;
    }

    public static String getCurrentUrl(HttpServletRequest request) {
        return getCurrentUrl(request, false);
    }

    /**
     * 获取当前访问的URI
     *
     * @param request
     * @param needQueryString
     * @return
     */
    public static String getCurrentUri(HttpServletRequest request, boolean needQueryString) {
        try {
            String url = request.getRequestURI();
            String queryString = request.getQueryString();
            if (!StringUtils.isEmpty(queryString)) {
                queryString = "?" + queryString;
                if (queryString.startsWith("&")) {
                    queryString = "?" + queryString.substring(1);
                }
            }
            if (!StringUtils.isEmpty(queryString) && needQueryString) {
                url = url + queryString;
            }
            return url;
        } catch (NullPointerException e) {
            logger.debug("无法取得HttpServletRequest对象：{}", e.getMessage());
        }
        return null;
    }

    public static String getCurrentUri(HttpServletRequest request) {
        return getCurrentUri(request, false);
    }

    /**
     * 提取服务器URL地址
     *
     * @param request
     * @return
     */
    public static String getDomain(HttpServletRequest request) {
        try {
            StringBuffer baseUrl = new StringBuffer();
            String scheme = request.getScheme();
            int port = request.getServerPort();

            baseUrl.append(scheme); // http, https
            baseUrl.append("://");
            baseUrl.append(request.getServerName());
            if ((scheme.equals("http") && port != 80) || (scheme.equals("https") && port != 443)) {
                baseUrl.append(':');
                baseUrl.append(request.getServerPort());
            }
            return baseUrl.toString();
        } catch (NullPointerException e) {
            logger.error("无法取得HttpServletRequest对象：{}", e.getMessage());
        }
        return null;
    }

    /**
     * 解析出url参数中的键值对 如 "index.jsp?Action=del&id=123"，解析出Action:del,id:123存入map中
     *
     * @param URL url地址
     * @return url请求参数部分
     */
    public static Map<String, String> URLRequest(String URL) {
        Map<String, String> mapRequest = new HashMap<String, String>();

        String[] arrSplit = null;

        String strUrlParam = TruncateUrlPage(URL);
        if (strUrlParam == null) {
            return mapRequest;
        }
        // 每个键值为一组 www.2cto.com
        arrSplit = strUrlParam.split("[&]");
        for (String strSplit : arrSplit) {
            String[] arrSplitEqual = null;
            arrSplitEqual = strSplit.split("[=]");

            // 解析出键值
            if (arrSplitEqual.length > 1) {
                // 正确解析
                mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);

            } else {
                if (arrSplitEqual[0] != "") {
                    // 只有参数没有值，不加入
                    mapRequest.put(arrSplitEqual[0], "");
                }
            }
        }
        return mapRequest;
    }

    /**
     * 去掉url中的路径，留下请求参数部分
     *
     * @param strURL url地址
     * @return url请求参数部分
     */
    private static String TruncateUrlPage(String strURL) {
        String strAllParam = null;
        String[] arrSplit = null;

        strURL = strURL.trim();

        arrSplit = strURL.split("[?]");
        if (strURL.length() > 1) {
            if (arrSplit.length > 1) {
                if (arrSplit[1] != null) {
                    strAllParam = arrSplit[1];
                }
            }
        }

        return strAllParam;
    }

    /**
     * export导出请求头设置
     *
     * @param response
     * @param workbook
     * @param fileName
     * @throws Exception
     */
    public static void download(HttpServletResponse response, Workbook workbook, String fileName) throws Exception {
        response.reset();
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/octet-stream; charset=UTF-8");
        // 设置暴露可以访问的头部信息，如果返回的filename想要被访问到
        // 通过Access-Control-Expose-Headers 指定暴露的属性 filename
        response.setHeader("Access-Control-Expose-Headers", "filename");
        response.setHeader("filename", URLEncoder.encode(fileName, "UTF-8"));
        response.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
        ServletOutputStream outStream = null;
        try {
            outStream = response.getOutputStream();
            workbook.write(outStream);
            outStream.flush();
        } finally {
            outStream.close();
        }
    }

}
